﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net.Sockets;
using System.Text.RegularExpressions;

namespace Dotnet.Code
{
    public delegate void CmdExecuteEventHandler(object sender, CmdExecuteEventArgs e);
    public class CmdExecuteEventArgs
    { 
        public CmdExecuteEventArgs()
        {

        }
        public string Data { get; set; }
        //public string IP { get; set; }
        //public int Port { get; set; }
    }


    public class CmdClass
    {
        //private Process _process = null;
        private CmdExecuteEventHandler _outputDataReceived = null;
        private CmdExecuteEventHandler _errorDataReceived = null;
        private string _fileName = "";

        public string FileName {set => _fileName = value; }

        public CmdClass()
        {

        }
        #region 事件处理
        public event CmdExecuteEventHandler OutputDataReceived
        {
            add { _outputDataReceived += value; }
            remove { _outputDataReceived -= value; }
        }
        public event CmdExecuteEventHandler ErrorDataReceived
        {
            add { _errorDataReceived += value; }
            remove { _errorDataReceived -= value; }
        }

        protected virtual void OnOutputDataReceived(CmdExecuteEventArgs e)
        {
            CmdExecuteEventHandler temp = System.Threading.Volatile.Read(ref _outputDataReceived);
            if (temp != null)
            {
                temp(this, e);
            }
        }
        protected virtual void OnErrorDataReceived(CmdExecuteEventArgs e)
        {
            CmdExecuteEventHandler temp = System.Threading.Volatile.Read(ref _errorDataReceived);
            if (temp != null)
            {
                temp(this, e);
            }
        }
        #endregion
        public void ExecuteCommand(string command)
        {
            InitCmd().StandardInput.WriteLine(command); //输入各种控制命令
        }

        private Process InitCmd(bool isShow=true)
        {
            Process _process = new Process();//创建进程对象
            ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.FileName = "cmd.exe";//设定需要执行的命令
            ///startInfo.Arguments = "/C " + command;//“/C”表示执行完命令后马上退出
            startInfo.UseShellExecute = false;//不使用系统外壳程序启动,不显示命令行运行窗口
            startInfo.RedirectStandardInput = true;//不重定向输入,重定向命令行的输入流，以便我们可以通过程序输入命令以模仿手工输入
            startInfo.RedirectStandardOutput = true; //重定向输出,输出流重定向，保证可以获取命令行执行命令后的输出结果
            startInfo.CreateNoWindow = isShow;//不创建窗口,　//不显示命令行运行窗口　　
            _process.StartInfo = startInfo;

            _process.Start();
            _process.BeginOutputReadLine();
            _process.OutputDataReceived += _process_OutputDataReceived;
            _process.ErrorDataReceived += _process_ErrorDataReceived;
            return _process;
        }

        public Process ExecuteDotnetCommand(string fileName)
        {
            Process process = InitCmd();
            string rootDir = System.IO.Path.GetPathRoot(fileName).Trim('\\');
            process.StandardInput.WriteLine(rootDir);
            string dir = System.IO.Path.GetDirectoryName(fileName).Replace(rootDir,"").Trim('\\');
            process.StandardInput.WriteLine($"cd {dir}");
            string dll = Path.GetFileName(fileName);
            process.StandardInput.WriteLine($"dotnet {dll}");
            return process;
        }
        public void ExecuteTelnetCommand(string ip,int port)
        {
            try
            {
                using (TcpClient tcpclient = new TcpClient())
                {
                    tcpclient.Connect(ip, port);
                    string info = $"{ip}:{port}测试连接成功";
                    OnOutputDataReceived(new CmdExecuteEventArgs() { Data = $"【{_fileName}】{ip}:{port} 连接成功" });
                }
            }
            catch (Exception ex)
            {
                OnErrorDataReceived(new CmdExecuteEventArgs() { Data = $"【{_fileName}】{ip}:{port} 连接失败【错误】{ex.Message}"  });
            }
        }
        private void _process_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            OnOutputDataReceived(new CmdExecuteEventArgs() { Data = $"【{_fileName}】{e.Data}" });
        }

        private void _process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            OnErrorDataReceived(new CmdExecuteEventArgs() { Data = $"【{_fileName}】{e.Data}" });
        }
        public bool KillPort(int port,out string msg)
        {
            msg = "";
            try
            {
                int pid = GetPidByPort(port);
                if (pid > 0)
                {
                    Process process = Process.GetProcessById(pid);
                    process.Kill();
                    msg = $"端口:{port} 进程 {pid} 已关闭";
                    return true;
                }
                else
                {
                    msg = $"端口:{port} 进程ID不存在";
                    return false;
                }
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                return false;
            }
        }


        private int GetPidByPort(int port)
        {
            int pid = 0;
            Process _process = new Process();//创建进程对象
            ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.FileName = "cmd.exe";//设定需要执行的命令
            ///startInfo.Arguments = "/C " + command;//“/C”表示执行完命令后马上退出
            startInfo.UseShellExecute = false;//不使用系统外壳程序启动,不显示命令行运行窗口
            startInfo.RedirectStandardInput = true;//不重定向输入,重定向命令行的输入流，以便我们可以通过程序输入命令以模仿手工输入
            startInfo.RedirectStandardOutput = true; //重定向输出,输出流重定向，保证可以获取命令行执行命令后的输出结果
            startInfo.CreateNoWindow = true;//不创建窗口,　//不显示命令行运行窗口　　
            _process.StartInfo = startInfo;
            _process.Start();
            _process.StandardInput.WriteLine(string.Format("netstat -ano|findstr \"{0}\"", port));
            _process.StandardInput.WriteLine("exit");
            StreamReader reader = _process.StandardOutput;
            string strLine = reader.ReadLine();
            while (!reader.EndOfStream)
            {
                strLine = strLine.Trim();
                Console.WriteLine(strLine);
                if (strLine.Length > 0 && ((strLine.Contains("TCP") || strLine.Contains("UDP"))))
                {
                    Regex r = new Regex(@"\s+");
                    string[] strArr = r.Split(strLine);
                    if (strArr.Length >= 4)
                    {
                        if (strArr[1].EndsWith(port.ToString()))
                        {
                            pid = Int32.Parse(strArr[4].Trim());
                            break;
                        }
                    }
                }
                strLine = reader.ReadLine();
            }
            _process.WaitForExit();
            reader.Close();
            _process.Close();
            return pid;
        }
    }
}
